/* -*- Mode:Prolog; coding:ISO-8859-1; -*- */

:- ensure_loaded([sicstus_support]). 


%@ dissection(+Atom, -Arguments, -ListAtom)
%@        Creates a list of lists containing all the structure of the literal or atom Literal.
%@        E. g. dissection(animal(+c, t(+s, ouch(-p, #q))), [+c, +s, -p, #q], [animal,+c,[t,+s,[ouch,-p,#q]]])

dissection(Atom, Args, ListAtom) :- 
        atom_to_list(Atom, [+, -, #], ListAtom),
        flatten(ListAtom, FlatListAtom),
        get_mode_arguments(FlatListAtom, [+, -, #], Args).


 
%@ atom_to_list(+Atom, +ListOfSpecialFunctors, -OutList)
%@        Transforms Atom into a list of lists where each non atomic term is tranformed in a list.
%@        The special functors are kept together and do not become a list
%@        E. g. 
%@        atom_to_list(animal(+c, t(+s, ouch(-p, #q))), [+, - , #], [animal,+c,[t,+s,[ouch,-p,#q]]])


atom_to_list(Atom, ListOfSpecialFunctors, [PredName | OutList]) :-
        Atom =.. [PredName | Rest], 
        x_atom_to_list(Rest, ListOfSpecialFunctors, OutList).


x_atom_to_list([], _, []).

x_atom_to_list([Current | Arguments], ListOfSpecialFunctors, [Current | OutList]) :-
        functor(Current, Functor, _),
        member(Functor, ListOfSpecialFunctors),
        !,
        x_atom_to_list(Arguments, ListOfSpecialFunctors, OutList).
                
x_atom_to_list([Current | Arguments], ListOfSpecialFunctors, [CurrentOut | OutList]) :-
        atom_to_list(Current, ListOfSpecialFunctors, CurrentOut), 
        x_atom_to_list(Arguments, ListOfSpecialFunctors, OutList).


%@ get_mode_arguments(+FlattenedListAtom, +ListOfSpecialFunctors, -OutList)
%@        Transforms Atom into a list of lists where each non atomic term is tranformed in a list.
%@        The special functors are kept together and do not become a list
%@        E. g. 
%@        get_arguments(animal(+c, t(+s, ouch(-p, #q))), [+, - , #], [+c,+s,-p,#q])


get_mode_arguments([], _, []).

get_mode_arguments([H | FlattenedListAtom], ListOfSpecialFunctors, [H | OutList]) :-
        functor(H, F, _), 
        member(F, ListOfSpecialFunctors),
        !,
        get_mode_arguments(FlattenedListAtom, ListOfSpecialFunctors, OutList).
        
get_mode_arguments([_ | FlattenedListAtom], ListOfSpecialFunctors, OutList) :-
        get_mode_arguments(FlattenedListAtom, ListOfSpecialFunctors, OutList).





%@ generate_vars_and_type_check(+Arguments, -InputVars,-OutputVars,-ConstantVars, -AllVars, -TypeCheck)
%@  (OBSOLETE DOCS)      Arguments are of the type +user, #time; Vars are of the type X, Y; TypeCheck are of the type user(X), time(Y).
%@        E. g. generate_vars_and_type_check([+c, +s, -p, #q], [A, B], [C], [D], [A, B, C, D], [c(A), s(B), p(C), q(D)]) 
generate_vars_and_type_check([], [] , [], [], [], [], [], []) :- !.

generate_vars_and_type_check(  [HArg | Arguments]  , [VarForHArg | TailIn] , Out, Const, [VarForHArg | Tail1] , FinalIn, FinalC, FinalO):- 
        HArg =.. [+, Type], !,
        TypeCheckForHArg =.. [Type, VarForHArg], 
        FinalIn = [TypeCheckForHArg | OtherConditions],
        generate_vars_and_type_check(Arguments, TailIn, Out, Const, Tail1, OtherConditions, FinalC, FinalO).

generate_vars_and_type_check(  [HArg | Arguments]  , In , [VarForHArg | TailOut], Const, [VarForHArg | Tail1] , FinalIn, FinalC, FinalO):- 
        HArg =.. [-, Type], !,
        TypeCheckForHArg =.. [Type, VarForHArg], 
        FinalO = [TypeCheckForHArg | OtherConditions],
        generate_vars_and_type_check(Arguments, In, TailOut, Const, Tail1, FinalIn,  FinalC, OtherConditions).
        
generate_vars_and_type_check(  [HArg | Arguments]  , In , Out, [VarForHArg | TailConst], [VarForHArg | Tail1] , FinalIn, FinalC, FinalO):- 
        HArg =.. [#, Type], 
        TypeCheckForHArg =.. [Type, VarForHArg], 
        FinalC = [TypeCheckForHArg | OtherConditions],
        generate_vars_and_type_check(Arguments, In, Out, TailConst, Tail1, FinalIn, OtherConditions, FinalO).
        
        

/*
variabilise(+DissectionedLiteral, +InputVars, +OutputVars, +ConstantVars, -VariabilisedDissectionedLiteral) 
Given a dissectioned literal and a set of variables it substitutes the arguments with appropriate variables. 
THE ORDER IS RELEVANT
*/


variabilise([PredicateName | Rest], Vars, [PredicateName | VariabilisedDissectionedLiteral]) :- 
        variabilise([PredicateName | Rest], Vars, _, [PredicateName | VariabilisedDissectionedLiteral]).


variabilise([PredicateName | Rest], Vars, RestVars, [PredicateName | VariabilisedDissectionedLiteral]):-
                variabilise_x(Rest, Vars, RestVars, VariabilisedDissectionedLiteral).


variabilise_x([H | T], Vars, RestVars, [This | VariabilisedDissectionedLiteral]) :- 
                is_list(H), !, 
                variabilise(H, Vars, RestVars, This),   
                variabilise_x(T, RestVars, _, VariabilisedDissectionedLiteral).

variabilise_x([], Vars, Vars, []).

variabilise_x([_ | T], [HI | TI], RestVars, [HI | VariabilisedDissectionedLiteral]) :-          
        variabilise_x(T, TI, RestVars, VariabilisedDissectionedLiteral).
        
     


variabilisenc([PredicateName | Rest], [PredicateName | VariabilisedDissectionedLiteral]):-
                variabilisenc_x(Rest,  VariabilisedDissectionedLiteral).


variabilisenc_x([H | T], [This | VariabilisedDissectionedLiteral]) :- 
                is_list(H), length(H, Q), Q > 1, !, 
                variabilisenc(H,  This),   
                variabilisenc_x(T,  VariabilisedDissectionedLiteral).

variabilisenc_x([],  []).

variabilisenc_x([_ | T],  [_ | VariabilisedDissectionedLiteral]) :-          
        variabilisenc_x(T,  VariabilisedDissectionedLiteral).

/*
make_literal(+List, -Literal)
        Opposite of dissection/2
*/
make_literal([PredicateName | Rest], Literal) :- 
        make_literal_list(Rest, ProcessedRest), 
        Literal =.. [PredicateName | ProcessedRest].

make_literal_list([H | T], [Literal | Rest]) :- 
        is_list(H), !, 
        make_literal(H, Literal), 
        make_literal_list(T, Rest).
        
make_literal_list([], []):- 
        !.
        
make_literal_list([H | T], [H | TRest]) :- 
        make_literal_list(T, TRest).



/*
Transforms an atom into an equivalent with variables instead of the arguments
                                                                             tvar(p(as,f(dasdas,q(dd)),ads), p(A,B,C)).
*/

tvar(X, Y) :-
        X =.. [H | Q],
        length(Q, L),
        length(R, L),
        make_literal([H | R], Y).